package com.telecom.restaurant.service;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.telecom.restaurant.constant.DefaultConstant;
import com.telecom.restaurant.dao.FoodDao;
import com.telecom.restaurant.domin.FoodSearchResult;
import com.telecom.restaurant.domin.PaginationResult;
import com.telecom.restaurant.enums.FoodTypeEnum;
import com.telecom.restaurant.model.FoodPO;
import com.telecom.restaurant.model.param.FoodSearchParam;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by qiqi on 2019/12/14.
 */
@Service
public class FoodService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    LoadingCache<Long, FoodPO> foodCache = CacheBuilder.newBuilder()
            .initialCapacity(100)
            .maximumSize(1000)
            .expireAfterAccess(24, TimeUnit.HOURS)//设置时间对象没有被读/写访问则对象从内存中删除
            //CacheLoader类 实现自动加载
            .build(new CacheLoader<Long, FoodPO>() {
                @Override
                public FoodPO load(Long foodId) {

                    FoodPO po = foodDao.selectByPrimaryKey(foodId);
                    if (po == null) {
                        po = DefaultConstant.EMPTY_FOOD;
                    }
                    return po;
                }
            });

    @Autowired
    private FoodDao foodDao;

    @Autowired
    private PictureService configService;


    public PaginationResult getFoodList(FoodSearchParam param) {

        PaginationResult result = new PaginationResult(param);

        int count = foodDao.countSearch(param);
        result.setCount(count);
        if (count == 0) {
            result.setDataList(Collections.emptyList());
        } else {
            List<FoodPO> foodList = foodDao.searchFood(param);
            result.setDataList(foodList);
        }

        return result;
    }

    public FoodSearchResult searchFood(FoodSearchParam param) {
        FoodSearchResult result = new FoodSearchResult();
        param.setPageNo(DefaultConstant.DEFAULT_PAGE_NO);
        param.setPageSize(DefaultConstant.DEFAULT_PAGE_SIZE);

        param.setType(FoodTypeEnum.PACKAGE_DISH.getCode());
        result.setPackageDish(foodDao.searchFood(param));

        param.setType(FoodTypeEnum.PACKAGE_MAIN.getCode());
        result.setPackageMain(foodDao.searchFood(param));

        param.setType(FoodTypeEnum.OTHER_DISH.getCode());
        result.setOtherDish(foodDao.searchFood(param));

        param.setType(FoodTypeEnum.OTHER_MAIN.getCode());
        result.setOtherMain(foodDao.searchFood(param));

        return result;
    }

    public Map<Long, FoodPO> getFoodByIds(Set<Long> foodIdSet) {
        if (foodIdSet == null || foodIdSet.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<Long, FoodPO> result = new HashMap<>();
        List<Long> sqlIds = null;
        for (Long foodId : foodIdSet) {
            FoodPO po = foodCache.getIfPresent(foodId);
            if (po == null || po.getId() == null) {
                if (sqlIds == null) {
                    sqlIds = new ArrayList<>();
                }
                sqlIds.add(foodId);
                continue;
            }
            result.put(foodId, po);
        }
        if (sqlIds != null && !sqlIds.isEmpty()) {
            // read for db
            List<FoodPO> foodList = foodDao.getByIds(sqlIds);
            if (!foodList.isEmpty()) {
                for (FoodPO foodFromDB : foodList) {
                    // add to map
                    result.put(foodFromDB.getId(), foodFromDB);
                    // set to cache
                    foodCache.put(foodFromDB.getId(), foodFromDB);

                }
            }
        }
        return result;
    }

    public FoodPO getOrInsertFood(Long restaurantId, String foodName, Integer type, Integer price) {
        FoodSearchParam param = new FoodSearchParam();
        param.setRestaurantId(restaurantId);
        param.setName(foodName);
        param.setType(type);


        List<FoodPO> foodPOList = foodDao.searchFood(param);
        if (CollectionUtils.isNotEmpty(foodPOList)) {
            return foodPOList.get(0);
        }

        FoodPO foodPO = new FoodPO();
        foodPO.setRestaurantId(restaurantId);
        foodPO.setName(foodName);
        foodPO.setType(type);
        foodPO.setPrice(price);
        foodDao.insert(foodPO);

        return foodPO;
    }

    public FoodPO getFoodById(Long foodId) {
        if (foodId == null) {
            return null;
        }
        FoodPO po = null;
        try {
            po = foodCache.get(foodId);
            if (po.getId() == null) {
                return null;
            }
            return po;
        } catch (Exception e) {
            logger.error("getFoodById id:{}", foodId, e);
        }
        return null;
    }
}
